package com.whpost.service.service.stamp.h5;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.whpost.service.dao.t.MyDao;
import com.whpost.service.dao.t.TWxInfoDao;
import com.whpost.service.dao.wx.TWxOrderDao;
import com.whpost.service.entity.tools.ResultInfo;
import com.whpost.service.entity.wx.TWxInfo;
import com.whpost.service.entity.wx.TWxOrder;
import com.whpost.service.service.stamp.StampOrderServices;
import com.whpost.service.tools.*;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 
 * @author yinzhuoyi
 *
 */
@Service
public class WxPay {

	@Resource
	private TWxOrderDao tWxOrderDao;
	@Resource
	private MyDao myDao;
	@Resource
	private StampOrderServices stampOrderServices;
	@Resource
	private TWxInfoDao tWxInfoDao;
	/**
	 * 参数签名
	 * @param characterEncoding
	 * @param parameters
	 * @param key
	 * @return
	 */
	public String createSign(String characterEncoding,SortedMap<Object,Object> parameters,String key)
	{
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			Object v = entry.getValue();
			if(null != v && !"".equals(v) 
				&& !"sign".equals(k) && !"key".equals(k)) {
			sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + key);
		ToolBean.info("加密前:"+sb);
		String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        ToolBean.info("加密后:"+sign);
		return sign;
	}

	public String getRequestXml(SortedMap<Object, Object> parameters) {
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		Set es = parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
				sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
			} else {
				sb.append("<" + k + ">" + v + "</" + k + ">");
			}
		}
		sb.append("</xml>");
		return sb.toString();
	}

    /**
     *
     * @param tbid
     * @param appid
     * @param mch_id
     * @param device_info
     * @param nonce_str
     * @param sign
     * @param body
     * @param detail
     * @param attach
     * @param out_trade_no
     * @param fee_type
     * @param total_fee
     * @param spbill_create_ip
     * @param time_start
     * @param time_expire
     * @param goods_tag
     * @param notify_url
     * @param trade_type
     * @param product_id
     * @param limit_pay
     * @param openid
     * @param tbname
     * @return
     */
	@Transactional
	public String createOrder(String tbid, String appid, String mch_id, String device_info, String nonce_str, String sign, String body, String detail, String attach, String out_trade_no, String fee_type, String total_fee, String spbill_create_ip, String time_start, String time_expire, String goods_tag, String notify_url, String trade_type, String product_id, String limit_pay, String openid, String tbname, TWxInfo tWxInfo)
	{
		String sendorderxml = "";
		String str="";
		String prepay_id="";
		try
		{
			//查询是否有可用的prepay_id，有的话，直接返回！参数：表+id+金额
			prepay_id = tWxOrderDao.checkPayId(tbname, tbid, total_fee,ToolBean.getToday());
			ToolBean.info("tbname["+tbname+"] - tbid["+tbid+"]查询是否有有效期的凭证："+prepay_id);
			if (StringUtils.isEmpty(prepay_id))	//没有找到，则看看有没有已经成功付款的！
			{
				prepay_id = tWxOrderDao.checkPayIdSuc(tbname, tbid, total_fee);
			}
			else
			{
				ToolBean.info("tbname["+tbname+"] - tbid["+tbid+"]查询到有效期内的prepay_id，直接返回："+prepay_id);
				return prepay_id;	//直接返回有效的凭证
			}
			if (StringUtils.isEmpty(prepay_id))	//付款的也没有找到，说明没有下单或者是前面下单的已经过期，需要重新下单。
			{
				//暂时先不删除已经下单的，过期了的，直接下新单！
				sendorderxml +="<xml>";
				sendorderxml +="<appid><![CDATA[%1$s]]></appid>";
				sendorderxml +="<mch_id><![CDATA[%2$s]]></mch_id>";
				sendorderxml +="<device_info><![CDATA[%3$s]]></device_info>";
				sendorderxml +="<nonce_str><![CDATA[%4$s]]></nonce_str>";
				sendorderxml +="<sign><![CDATA[%5$s]]></sign>";
				sendorderxml +="<body><![CDATA[%6$s]]></body>";
				sendorderxml +="<detail><![CDATA[%7$s]]></detail>";
				sendorderxml +="<attach><![CDATA[%8$s]]></attach>";
				sendorderxml +="<out_trade_no><![CDATA[%9$s]]></out_trade_no>";
				sendorderxml +="<fee_type><![CDATA[%10$s]]></fee_type>";
				sendorderxml +="<total_fee><![CDATA[%11$s]]></total_fee>";
				sendorderxml +="<spbill_create_ip><![CDATA[%12$s]]></spbill_create_ip>";
				sendorderxml +="<time_start><![CDATA[%13$s]]></time_start>";
				sendorderxml +="<time_expire><![CDATA[%14$s]]></time_expire>";
				sendorderxml +="<goods_tag><![CDATA[%15$s]]></goods_tag>";
				sendorderxml +="<notify_url><![CDATA[%16$s]]></notify_url>";
				sendorderxml +="<trade_type><![CDATA[%17$s]]></trade_type>";
				sendorderxml +="<product_id><![CDATA[%18$s]]></product_id>";
				sendorderxml +="<limit_pay><![CDATA[%19$s]]></limit_pay>";
				sendorderxml +="<openid><![CDATA[%20$s]]></openid>";
				sendorderxml +="</xml>";
				str = String.format(sendorderxml,appid, mch_id, device_info, nonce_str, sign, body, detail, attach, out_trade_no, fee_type,total_fee, spbill_create_ip, time_start, time_expire, goods_tag, notify_url, trade_type, product_id, limit_pay, openid);
				ToolBean.info("发送的内容:"+str);
				
				//写入wx_order
				TWxOrder wxOrder = new TWxOrder();

				wxOrder.setZblsh(Long.parseLong(tbid));
				wxOrder.setSendAppid(appid);
				wxOrder.setSendMchId(mch_id);
				wxOrder.setSendOutTradeNo(out_trade_no);
				wxOrder.setSendNotifyUrl(notify_url);
				wxOrder.setSendFeeType(fee_type);
				wxOrder.setSendTotalFee(total_fee);
				wxOrder.setSendTimeStart(time_start);
				wxOrder.setSendTimeExpire(time_expire);
				wxOrder.setSendTradeType(trade_type);
				wxOrder.setSendOpenid(openid);
				wxOrder.setTname(tbname);
				wxOrder.setWxId(tWxInfo.getLsh());
				
				int sl = tWxOrderDao.insert(wxOrder);
				
				if (sl<=0)
				{
					prepay_id = "";
				}
				else
				{
					ToolBean.info("tbname["+tbname+"] - tbid["+tbid+"]wx_order完成，开始微信下单...");
					WxTools wxTools = new WxTools();
					String a = wxTools.httpRequestxml("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", str);
					ToolBean.info("返回结果 xml:"+a);
					prepay_id = ReaderXmlForDOM.parse(a, "prepay_id");
					String return_code = ReaderXmlForDOM.parse(a, "return_code");
					String return_code_url = ReaderXmlForDOM.parse(a, "code_url");
					if (return_code.equals("SUCCESS"))
					{
						ToolBean.info("微信下单完成，开始回写订单表...");
						tWxOrderDao.updateWxOrderByRtnJson(prepay_id, wxOrder.getLsh(), return_code, return_code_url);
						ToolBean.info("订单表回写完成，返回凭证..."+prepay_id);
					}
					else
					{
						//删除wx_order;
						ToolBean.info("微信下单失败，删除...");
						int sqlCount = tWxOrderDao.delFailWxOrder(out_trade_no);
						ToolBean.info("微信下单失败，删除完成！删除数量："+sqlCount);
					}
				}
				return prepay_id;
			}
			else
			{
				ToolBean.info("查询到已付款的prepay_id，直接返回："+prepay_id);
				return prepay_id;
			}
		}
		catch (Exception e) 
		{
			ToolBean.info("createOrder发生错误！"+e.toString());
			throw new RuntimeException("微信下单发生错误！"+e.toString());
		}
	}

	@Transactional
	public String createOrderH5(String tbid,String appid,String mch_id,String device_info,String nonce_str,String sign,String body,String detail,String attach,String out_trade_no,String fee_type,String total_fee,String spbill_create_ip,String time_start,String time_expire,String goods_tag,String notify_url,String trade_type,String product_id,String limit_pay,String tbname,String scene_info)
	{
		String sendorderxml = "";
		String str="";
		String payurl="";
		try
		{
				//暂时先不删除已经下单的，过期了的，直接下新单！

				sendorderxml +="<xml>";
				sendorderxml +="<appid><![CDATA[%1$s]]></appid>";
				sendorderxml +="<mch_id><![CDATA[%2$s]]></mch_id>";
				sendorderxml +="<device_info><![CDATA[%3$s]]></device_info>";
				sendorderxml +="<nonce_str><![CDATA[%4$s]]></nonce_str>";
				sendorderxml +="<sign><![CDATA[%5$s]]></sign>";
				sendorderxml +="<body><![CDATA[%6$s]]></body>";
				sendorderxml +="<detail><![CDATA[%7$s]]></detail>";
				sendorderxml +="<attach><![CDATA[%8$s]]></attach>";
				sendorderxml +="<out_trade_no><![CDATA[%9$s]]></out_trade_no>";
				sendorderxml +="<fee_type><![CDATA[%10$s]]></fee_type>";
				sendorderxml +="<total_fee><![CDATA[%11$s]]></total_fee>";
				sendorderxml +="<spbill_create_ip><![CDATA[%12$s]]></spbill_create_ip>";
				sendorderxml +="<time_start><![CDATA[%13$s]]></time_start>";
				sendorderxml +="<time_expire><![CDATA[%14$s]]></time_expire>";
				sendorderxml +="<goods_tag><![CDATA[%15$s]]></goods_tag>";
				sendorderxml +="<notify_url><![CDATA[%16$s]]></notify_url>";
				sendorderxml +="<trade_type><![CDATA[%17$s]]></trade_type>";
				sendorderxml +="<product_id><![CDATA[%18$s]]></product_id>";
				sendorderxml +="<limit_pay><![CDATA[%19$s]]></limit_pay>";
			    sendorderxml +="<scene_info><![CDATA[%20$s]]></scene_info>";
				sendorderxml +="</xml>";
				str = String.format(sendorderxml,appid, mch_id, device_info, nonce_str, sign, body, detail, attach, out_trade_no, fee_type,total_fee, spbill_create_ip, time_start, time_expire, goods_tag, notify_url, trade_type, product_id, limit_pay,scene_info);
				ToolBean.info("发送的内容:"+str);

				//写入wx_order
				TWxOrder wxOrder = new TWxOrder();

				wxOrder.setZblsh(Long.parseLong(tbid));
				wxOrder.setSendAppid(appid);
				wxOrder.setSendMchId(mch_id);
				wxOrder.setSendOutTradeNo(out_trade_no);
				wxOrder.setSendFeeType(fee_type);
				wxOrder.setSendTotalFee(total_fee);
				wxOrder.setSendTimeStart(time_start);
				wxOrder.setSendTimeExpire(time_expire);
				wxOrder.setSendTradeType(trade_type);
				wxOrder.setSendOpenid(null);
				wxOrder.setTname(tbname);

				int sl = tWxOrderDao.insert(wxOrder);

				if (sl<=0)
				{
					payurl = "";
				}
				else
				{
					ToolBean.info("tbname["+tbname+"] - tbid["+tbid+"]wx_order完成，开始微信下单...");
					WxTools wxTools = new WxTools();
					String a = wxTools.httpRequestxml("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", str);
					ToolBean.info("返回结果 xml:"+a);
					payurl = ReaderXmlForDOM.parse(a, "mweb_url");

				}
				return payurl;
		}
		catch (Exception e)
		{
			ToolBean.info("createOrder发生错误！"+e.toString());
			throw new RuntimeException("微信下单发生错误！"+e.toString());
		}
	}


	/**
	 *
	 * @param send_out_trade_no
	 * @param transaction_id
	 * @return
	 */
	@Transactional
	public String paySucDone(String send_out_trade_no,String transaction_id)
	{
		TWxOrder tWxOrder = new TWxOrder();
		try
		{
			if(StringUtils.isEmpty(send_out_trade_no) || StringUtils.isEmpty(transaction_id))
			{
				return "{\"code\":\"30001\",\"msg\":\"订单参数丢失！\"}";
			}

			tWxOrder = tWxOrderDao.selectOne(new QueryWrapper<TWxOrder>().eq("send_out_trade_no",send_out_trade_no));
			String ywclState = tWxOrder.getYwclState();
			if (StringUtils.isEmpty(ywclState)) ywclState = "0";
			if (ywclState.equals("1"))
			{
				return "{\"code\":\"30002\",\"msg\":\"订单业务已经完成，不要重复执行！\"}";
			}
			else{

				// 先更新wx_order表，设置支付完成标志为1
				ToolBean.info("开始更新t_wx_order["+send_out_trade_no+"]支付标志和微信订单号...begin");
				int sl = tWxOrderDao.updateWxOrderByPaySuc(send_out_trade_no, transaction_id);
				if (sl<=0)
				{
					ToolBean.info("开始更新t_wx_order["+send_out_trade_no+"]支付标志和微信订单号...begin...更新的数量["+sl+"]");
					return "{\"code\":\"30003\",\"msg\":\"没有可更新的订单信息，可能已经完成业务！\"}";
				}
				ToolBean.info("开始更新t_wx_order["+send_out_trade_no+"]支付标志和微信订单号..end");

				//开始处理业务逻辑
				ToolBean.info("开始处理订单表[订单主键："+tWxOrder.getZblsh()+"]业务逻辑...begin");
				String rtn = "";
				rtn = stampOrderServices.dealDdxxByWxOrder(tWxOrder);
				ToolBean.info("开始处理订单表[订单主键："+tWxOrder.getZblsh()+"]业务逻辑...end 返回["+rtn+"]");
			}
			return "{\"code\":\"200\",\"msg\":\"付款完成！\"}";
		}
		catch (Exception e)
		{
			ToolBean.info("paySucDone发生错误！"+e.toString());
			throw new RuntimeException("支付通知页面错误！"+e.toString());
		}
	}

	/**
	 * 退款
	 * @param out_trade_no
	 * @return
	 */
	public ResultInfo wxTk(String out_trade_no)
	{
		TWxOrder tWxOrder = new TWxOrder();
		try
		{
			tWxOrder = tWxOrderDao.selectOne(new QueryWrapper<TWxOrder>().eq("send_out_trade_no",out_trade_no));
			if (tWxOrder!=null)
			{
				TWxInfo tWxInfo = tWxInfoDao.selectById(tWxOrder.getWxId());
				String appid=tWxInfo.getAppid();
				String mch_id=tWxInfo.getMchId();
				String rq = ToolBean.getTodayStr("yyyyMMddHHmmss");
				String device_info="WEB";
				String nonce_str=ToolBean.getRandomString(30);
				String detail="";
				String attach="";
				String out_refund_no=out_trade_no+"_"+"tk"+rq;
				ToolBean.info("退款商户号为："+out_refund_no);
				String total_fee=tWxOrder.getSendTotalFee();
				String refund_fee = tWxOrder.getSendTotalFee();
				String key= tWxInfo.getAppkey();
				String refund_fee_type= "CNY";
				SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
				parameters.put("appid", appid);
				parameters.put("mch_id", mch_id);
				parameters.put("device_info", device_info);
				parameters.put("nonce_str", nonce_str);
				parameters.put("out_trade_no", out_trade_no);
				parameters.put("total_fee", total_fee);
				parameters.put("out_refund_no", out_refund_no);
				parameters.put("refund_fee", refund_fee);
				parameters.put("refund_fee_type", refund_fee_type);
				parameters.put("op_user_id", "001");
				String sign=this.createSign("UTF-8", parameters, key);
				parameters.put("sign",sign);
				String requestXML = this.getRequestXml(parameters);
				ToolBean.info("退款发起参数：\n"+requestXML);
				//发起退款
				String responseXml = WeChatConfigUtil.doRefund(mch_id , "https://api.mch.weixin.qq.com/secapi/pay/refund", requestXML );
				ToolBean.info("退款返回：\n"+responseXml);
				String return_code = ReaderXmlForDOM.parse(responseXml, "return_code");
				ToolBean.info("退款返回return_code："+return_code);
				if (return_code.toUpperCase().equals("SUCCESS")){
					return new ResultInfo(0,"退款成功！",null);
				}else{
					return new ResultInfo(500,"退款失败！",null);
				}
			}else{
				return new ResultInfo(500,"没有找到对应的支付订单！",null);
			}

		}
		catch (Exception e)
		{
			ToolBean.info("wxTk退款完成发生错误！"+e.toString());
			throw new RuntimeException("wxTk退款完成错误！"+e.toString());
		}
	}
}